//
//  CS_ImportMusicFromLibraryViewController.swift
//  NewSS
//
//  Created by 杨馥瑞 on 2021/11/3.
//

import UIKit

class CS_ImportMusicFromLibraryViewController: UIViewController, UITabBarDelegate, UITableViewDataSource, UITableViewDelegate {
    
    private(set) var viewModel = CS_ImportMusicFromLibraryViewModel()
    private lazy var _searchBarHeader: SearchBarHeader = _getSearchBarHeader()
    private lazy var _listView: UITableView = _getMusicListTableView()

    override func viewDidLoad() {
        super.viewDidLoad()
        _initUI()
        _initData()
        _initListener()
    }
    
    // MARK: - UITableViewDataSource, UITableViewDelegate
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModel.displayMusics.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: MusicCell = tableView.dequeueReusableCell(indexPath: indexPath)
        let music = viewModel.displayMusics[indexPath.row]
        cell.setTitle(music.musicName)
        cell.setSubTitle(music.singerName)
        if CS_ImportMusicRequest.musicIsDownloading(music) {
            cell.setStatus(.downloading)
        }
        else if CS_ImportMusicRequest.musicIsDownloaded(music) {
            cell.setStatus(.downloaded)
        }
        else {
            cell.setStatus(.normal)
        }
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let music = viewModel.displayMusics[indexPath.row]
        if CS_ImportMusicRequest.musicIsDownloaded(music) || CS_ImportMusicRequest.musicIsDownloading(music) {
            return
        }
        CJLoading.show(toast: "已添加到歌单")
        viewModel.downloadMusic(viewModel.displayMusics[indexPath.row]) { progress in
            let cell = tableView.cellForRow(at: indexPath) as? MusicCell
            cell?.setStatus(.downloading)
        } complete: { isSuccess in
            let cell = tableView.cellForRow(at: indexPath) as? MusicCell
            cell?.setStatus(isSuccess ? .downloaded : .downloadFail)
        }
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        _searchBarHeader.resignSearchBarFirstResponder()
    }
    
    // MARK: - 私有方法
    
    private func _initUI() {
        view.backgroundColor = .white
        
        view.addSubview(_listView)
        _listView.tableHeaderView = _searchBarHeader
        
        _listView.snp.makeConstraints { $0.edges.equalToSuperview() }
        _searchBarHeader.frame = CGRect(x: 0, y: 0, width: _listView.bounds.size.width, height: fixScale(52))
    }
    
    private func _initData() {
        viewModel.fetchHotMusics()
    }
    
    private func _initListener() {
        viewModel.displayMusicsDidUpdated = { [weak self] in
            DispatchQueue.main.async {
                self?._listView.reloadData()
            }
        }
        
        _searchBarHeader.searchTextDidChanged = { [weak self] keyword in
            self?.viewModel.searchMusic(keyword)
        }
        
        _searchBarHeader.clickCancelCallback = { [weak self] in
            self?.dismiss(animated: true, completion: nil)
        }
    }
    
    private func _getSearchBarHeader() -> SearchBarHeader {
        return SearchBarHeader()
    }
    
    private func _getMusicListTableView() -> UITableView {
        let tableView = UITableView()
        tableView.delegate = self
        tableView.dataSource = self
        tableView.rowHeight = fixScale(62)
        tableView.register(MusicCell.self)
        tableView.tableFooterView = UIView()
        return tableView
    }

}

class CS_ImportMusicFromLibraryViewModel: NSObject {
    
    var displayMusicsDidUpdated: (()->Void)?
    var displayMusics: [CS_MusicModel] { isInTheSearch ? searchMusics : hotMusics }
    
    private var hotMusics = [CS_MusicModel]()
    private var searchMusics = [CS_MusicModel]()
    private var searchKeyword = ""
    private var isInTheSearch: Bool { !searchKeyword.isEmpty }
    private lazy var operationQueue: OperationQueue = _getOperationQueue()
    private var canSearch = true
    
    // MARK: - 外部方法
    
    func fetchHotMusics() {
        CS_ImportMusicRequest.fetchHotMusicListFromRemote { [weak self] musicList in
            self?.hotMusics = musicList == nil ? [CS_MusicModel]() : musicList!
            self?.displayMusicsDidUpdated?()
        }
    }
    
    func searchMusic(_ keyword: String) {
        func searchMusicRequest(_ keyword: String) {
            operationQueue.addOperation { [weak self] in
                CS_ImportMusicRequest.searchMusic(keyword) { musicList in
                    self?.searchMusics = musicList == nil ? [CS_MusicModel]() : musicList!
                    self?.displayMusicsDidUpdated?()
                } cancel: {
                    
                }
            }
        }
        
        searchKeyword = keyword
        keyword.isEmpty ? fetchHotMusics() : searchMusicRequest(keyword)
    }
    
    func downloadMusic(_ music: CS_MusicModel, progressBlock: ((CGFloat)->Void)?, complete: @escaping (Bool)->Void) {
        CS_ImportMusicRequest.downloadMusic(music) { progress in
            progressBlock?(progress)
        } complete: { isSuccess in
            complete(isSuccess)
        }

    }
    
    // MARK: - 私有方法
    
    private func _finishRequest() {
        
    }
    
    private func _getOperationQueue() -> OperationQueue {
        let operationQueue = OperationQueue()
        operationQueue.name = "ik.music.search.result.queue"
        operationQueue.maxConcurrentOperationCount = 1
        return operationQueue
    }
    
}

class CS_ImportMusicFromLibraryCellModel {
    
    enum CellStatus {
        case normal
        case downloading         // 下载中
        case downloaded          // 已下载
        case downloadFail        // 下载失败
    }
    
    var music: CS_MusicModel?
    var status = CellStatus.normal
    
    init(music: CS_MusicModel?, status: CellStatus = .normal) {
        self.music = music
        self.status = status
    }
    
}

private class SearchBarHeader: UIView, UISearchBarDelegate {
    
    // MARK: - 属性
    
    var clickCancelCallback: (()->Void)?
    var searchTextDidChanged: ((String)->Void)?
    
    private lazy var _searchBar: UISearchBar = _getSearchBar()
    private lazy var _cancelButton: UIButton = _getCancelButton()
    
    // MARK: - 初始化
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        _initViews()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - 外部方法
    
    func resignSearchBarFirstResponder() {
        _searchBar.resignFirstResponder()
    }
    
    // MARK: - 事件
    
    @objc private func _clickCancel() {
        clickCancelCallback?()
    }
    
    @objc private func _searchCallback(_ keyword: String) {
        searchTextDidChanged?(keyword)
    }
    
    // MARK: - UISearchBarDelegate
    
    private var shouldResponseInput = true
    private var lastSearchText = ""
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        // 1.记录输入值
        lastSearchText = searchText
        // 2.如果可响应，执行回调
        if shouldResponseInput {
            _searchCallback(lastSearchText)
            shouldResponseInput = false
            // 3.限制1s内仅响应一次，并根据记录的最后一个值进行回调
            DispatchQueue.main.asyncAfter(deadline: .now()+1) {
                self.shouldResponseInput = true
                if self.lastSearchText != searchText {
                    self._searchCallback(self.lastSearchText)
                }
            }
        }
    }
    
    // MARK: - 私有方法
    
    private func _initViews() {
        addSubview(_searchBar)
        addSubview(_cancelButton)
        
        _searchBar.snp.makeConstraints { make in
            make.left.equalTo(fixScale(16))
            make.top.equalTo(fixScale(8))
            make.right.equalTo(_cancelButton.snp.left).offset(-fixScale(8))
            make.height.equalTo(fixScale(36))
        }
        
        _cancelButton.snp.makeConstraints { make in
            make.right.equalTo(-fixScale(16))
            make.width.equalTo(fixScale(40))
            make.height.equalTo(fixScale(40))
            make.centerY.equalTo(_searchBar)
        }
    }
    
    private func _getSearchBar() -> UISearchBar {
        let searchBar = UISearchBar()
        searchBar.tintColor = .mainColor
        searchBar.barTintColor = .white
        searchBar.placeholder = "搜索歌曲"
        searchBar.showsCancelButton = false
        searchBar.backgroundImage = UIImage()
        searchBar.delegate = self
        return searchBar
    }
    
    private func _getCancelButton() -> UIButton {
        let button = UIButton(type: .custom)
        button.setTitle("取消", for: .normal)
        button.setTitleColor(.mainColor, for: .normal)
        button.titleLabel?.font = .systemFont(ofSize: 15)
        button.addTarget(self, action: #selector(_clickCancel), for: .touchUpInside)
        return button
    }
    
}

private class MusicCell: UITableViewCell {
    
    private lazy var _titleLabel: UILabel = _getTitleLabel()
    private lazy var _subTitleLabel: UILabel = _getSubTitleLabel()
    private lazy var _downloadButton: UIButton = _getDownloadButton()
    private lazy var _dowloadedIcon: UIImageView = _getDownloadedIcon()
    
    // MARK: - 初始化
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        _initViews()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - 外部方法
    
    func setTitle(_ title: String) {
        _titleLabel.text = title
    }
    
    func setSubTitle(_ subTitle: String) {
        _subTitleLabel.text = subTitle
    }
    
    func setStatus(_ status: CS_ImportMusicFromLibraryCellModel.CellStatus) {
        func imageForDownloadButton(_ status: CS_ImportMusicFromLibraryCellModel.CellStatus) -> UIImage? {
            switch status {
            case .normal, .downloadFail: return UIImage(named: "music_cell_download")
            case .downloading: return UIImage(named: "music_cell_downloading")
            case .downloaded: return nil
            }
        }
        
        func changeDownloadButtonIconAndStartAnimation(byStatus status: CS_ImportMusicFromLibraryCellModel.CellStatus) {
            _downloadButton.setImage(imageForDownloadButton(status), for: .normal)
            status == .downloading ? _downloadButton.startRotationAnimation() : _downloadButton.stopRotationAnimation()
        }
        
        func reMakeTitleLabelAndDownloadedIconLayout(byStatus status: CS_ImportMusicFromLibraryCellModel.CellStatus) {
            if status == .downloaded {
                _dowloadedIcon.snp.remakeConstraints { make in
                    make.left.equalTo(fixScale(16))
                    make.size.equalTo(fixScale(13))
                    make.centerY.equalTo(_subTitleLabel)
                }
                _subTitleLabel.snp.remakeConstraints { make in
                    make.left.equalTo(_dowloadedIcon.snp.right).offset(fixScale(4))
                    make.right.equalTo(_titleLabel)
                    make.top.equalTo(_titleLabel.snp.bottom).offset(fixScale(4))
                }
                _dowloadedIcon.isHidden = false
            }
            else {
                _dowloadedIcon.snp.remakeConstraints { make in
                    make.left.equalTo(fixScale(16))
                    make.size.equalTo(0)
                    make.centerY.equalTo(_subTitleLabel)
                }
                _subTitleLabel.snp.makeConstraints { make in
                    make.left.right.equalTo(_titleLabel)
                    make.top.equalTo(_titleLabel.snp.bottom).offset(fixScale(4))
                }
                _dowloadedIcon.isHidden = true
            }
        }
        
        changeDownloadButtonIconAndStartAnimation(byStatus: status)
        reMakeTitleLabelAndDownloadedIconLayout(byStatus: status)
    }
    
    // MARK: - 私有方法
    
    private func _initViews() {
        contentView.backgroundColor = .white
        backgroundColor = .white
        
        contentView.addSubview(_dowloadedIcon)
        contentView.addSubview(_titleLabel)
        contentView.addSubview(_subTitleLabel)
        contentView.addSubview(_downloadButton)
        
        _dowloadedIcon.snp.makeConstraints { make in
            make.left.equalTo(fixScale(16))
            make.size.equalTo(0)
            make.centerY.equalTo(_subTitleLabel)
        }
        
        _titleLabel.snp.makeConstraints { make in
            make.left.equalTo(fixScale(16))
            make.right.equalTo(_downloadButton.snp.left).offset(fixScale(-16))
            make.top.equalTo(fixScale(13))
        }
        
        _subTitleLabel.snp.makeConstraints { make in
            make.left.right.equalTo(_titleLabel)
            make.top.equalTo(_titleLabel.snp.bottom).offset(fixScale(4))
        }
        
        _downloadButton.snp.makeConstraints { make in
            make.size.equalTo(fixScale(50))
            make.centerY.equalToSuperview()
            make.right.equalTo(fixScale(-10))
        }
    }
    
    // MARK: - 懒加载
    
    private func _getTitleLabel() -> UILabel {
        let label = UILabel()
        label.font = kFont(kPingFangSCRegular, 15)
        label.textColor = .colorT1
        return label
    }
    
    private func _getSubTitleLabel() -> UILabel {
        let label = UILabel()
        label.font = kFont(kPingFangSCRegular, 13)
        label.textColor = .hexString("#AEAEAE")
        return label
    }
    
    private func _getDownloadButton() -> UIButton {
        let button = UIButton(type: .custom)
        button.setImage(UIImage(named: "music_cell_download"), for: .normal)
        button.isUserInteractionEnabled = false
        return button
    }
    
    private func _getDownloadedIcon() -> UIImageView {
        let imageView = UIImageView()
        imageView.image = UIImage(named: "music_cell_downloaded")
        imageView.isHidden = true
        return imageView
    }
    
}

private extension UIView {
    /// 顺时针旋转视图
    func startRotationAnimation(animationDuration: TimeInterval = 1) {
        // 不重复添加
        guard layer.animation(forKey: "cs.rorationAnimation") == nil else { return }
        
        let rorationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
        rorationAnimation.fromValue = 0
        rorationAnimation.toValue = Double.pi * 2
        rorationAnimation.duration = animationDuration
        rorationAnimation.isCumulative = true
        rorationAnimation.repeatCount = .greatestFiniteMagnitude
        layer.add(rorationAnimation, forKey: "cs.rorationAnimation")
    }
    
    /// 移除视图的旋转动画，与 cs_startRotationAnimation 对应
    func stopRotationAnimation() {
        layer.removeAnimation(forKey: "cs.rorationAnimation")
    }
}
